#!/usr/bin/python
# Copyright 2009 Alex K (wtwf.com) All rights reserved.

"""Watch lirc remotes and take action if required.

Usage: %(PROGRAM)s
"""

import getopt
import getpass
import httplib
import logging
import os
import sys
import urllib
import urllib2
import subprocess
import time

""" control urls look like this
http://192.168.2.22:8080/action/Entertainment?action=remote&room=AV Closet&button=VOL%2B&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver

http://192.168.2.22:8080/action/Entertainment?action=remote&room=AV Closet&button=Tuner&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver

        20.067    6892    4363    17 requests


followed by

VOL%2B&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
VOL-&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
Tuner&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
TiVo&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
TV&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
Amp On&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
Amp Off&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
Amp On&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
CD&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
DVD/MP3&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
DVD/MP3&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver
Mute&devpath=controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver

pause&devpath=controllers.D3K.room.AV Closet.av.AV Closet PVR

and for the relays:


http://192.168.2.22:8080/Util/sendCMDCommands/logs.D3K.Relays.Relay%201?command=Not%20Energized
http://192.168.2.22:8080/Util/sendCMDCommands/logs.D3K.Relays.Relay%201?command=Energized

"""



class Controller(object):
  """Controls something.
  """

  def Command(self, device):
    """Execute a command for device."""
    raise NotImplementedError("abstract method: implement in subclasses")

class Device(object):
  """A Device to be controlled"""
  pass

class D3KDevice(Device):
  """A Device controlled by a a Destiny Networks Domain 3000."""
  path = None  # a path to the object
  commands = tuple()  # what commands can be run
  relay = None  # what relay do we need to turn on for this device

  def __init__(self, controller):
    self.controller = controller

  def Command(self, cmd):
    self.controller.Command(self, cmd)


class D3KReceiver(D3KDevice):
  path = 'controllers.D3K.room.AV Closet.av.AV Closet AV Surround receiver'
  commands = ('VOL+',
              'VOL-',
              'Tuner',
              'TiVo',
              'TV',
              'Amp On',
              'Amp Off',
              'CD',
              'DVD/MP3',
              'Mute',)


class D3KTivo(D3KDevice):
  path = 'controllers.D3K.room.AV Closet.av.AV Closet PVR'
  commands = ('pause', 'play')
  relay = 1

  def TurnOn(self, receiver=None):
    if receiver:
      receiver.Command('Off')
    self.controller.MomentaryOnRelay(self.relay)


class D3KXbmc(D3KDevice):
  relay = 3

  def TurnOn(self, receiver=None):
    if receiver:
      receiver.Command('On')
    self.controller.MomentaryOnRelay(self.relay)
    if receiver:
      receiver.Command('DVD/MP3')


class D3KController(Controller):
  """A Destiny Networks Domain 3000 Home Automation Controller."""

  server = 'http://192.168.2.22:8080'

  base_url = ('%s/action/Entertainment?'
              'action=remote&room=AV+Closet&button=' % server)

  def Command(self, device, command):
    """Hit the url on the destiny server to cause the action to happen."""

    url = ('%s%s&devpath=%s' %
           (self.base_url, urllib.quote(command), urllib.quote(device.path)))
    self.HitUrl(url)

  def Relay(self, relay_number, state):
    """Control a relay"""
    if state:
      state_string = 'Energized'
    else:
      state_string = 'Not Energized'

    url = ('%s/Util/sendCMDCommands/logs.D3K.Relays.Relay%%20%d?command=%s' %
           (self.server, relay_number, urllib.quote(state_string)))
    self.HitUrl(url)

  def MomentaryOnRelay(self, relay_number):
    """Turn a relay on for half a second."""
    self.Relay(relay_number, True)
    time.sleep(0.5)
    self.Relay(relay_number, False)

  def AllRelays(self, state):
    for x in range(1, 5):
      self.Relay(x, state)

  def HitUrl(self, url):
    print url
    u = urllib.urlopen(url)
    u.close()


def usage(code=True, msg=''):
  if code:
    fd = sys.stderr
  else:
    fd = sys.stdout
  PROGRAM = os.path.basename(sys.argv[0])
  print >> fd, __doc__ % locals()
  if msg:
    print >> fd, msg
  sys.exit(code)


def main():
  """The main function runs the Bookmarks application with the provided
  username and password values.  Authentication credentials are required.
  NOTE:  It is recommended that you run this sample using a test account."""

  logging.basicConfig()
  logging.getLogger().setLevel(logging.DEBUG)
  logging.debug("Starting %s", " ".join(sys.argv))

  # parse command line options
  try:
    opts, args = getopt.getopt(sys.argv[1:], "e:p:u:f:", ["email=", "password=",
                                                          "user=", "file="])
  except getopt.error, msg:
    usage(msg=msg)

  d3k = D3KController()
  tivo = D3KTivo(d3k)
  receiver = D3KReceiver(d3k)
  xbmc = D3KXbmc(d3k)
  currently_on = None

  # turn all relays off
  d3k.AllRelays(False)

  cmd = '/usr/bin/irw'
  # cmd = '/bin/ls -l'
  irw = subprocess.Popen(cmd, stdout=subprocess.PIPE)
  while True:
    line = irw.stdout.readline().rstrip()
    if not line:
      break
    (id, state, but, dev) = line.split()
    if state != '00':
      continue
    if dev == 'Tivo_Series1':
      if but in ('TIVO', 'PAUSE', 'PLAY'):
        if currently_on != tivo:
          tivo.TurnOn()
          currently_on = tivo
      else:
        logging.debug("Ignoring Tivo: %s", but)
    elif dev == 'mceusb':
      if but in ('Home', 'Blue', 'DVD'):
        if currently_on != xbmc:
          xbmc.TurnOn()
          currently_on = xbmc
        print 'Possibly change state to htpc'
      elif but == 'VolUp':
        receiver.Command("VOL+")
      elif but == 'VolDown':
        receiver.Command("VOL-")
      elif but == 'Mute':
        receiver.Command('Mute')
      else:
        logging.debug("Ignoring HTPC: %s", but)



if __name__ == '__main__':
  main()
